package utils;

import org.apache.commons.io.filefilter.AndFileFilter;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.monitor.FileAlterationObserver;

import java.io.*;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

/**
 * @program: PostGirl-panent
 * @description: 文件处理助手
 * @author: Cheng Zhi
 * @create: 2022-10-04 12:38
 **/
public class FileUtils {

    /**
     * 读取指定文件块
     * @param file
     * @param startPoint 起始位置
     * @param blockSize
     * @return
     */
    public static String readBlock(File file, long startPoint, int blockSize) {

        try {
            RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
            // 跳转到指定位置
            randomAccessFile.seek(startPoint);
            // 从指定位置读取指定大小的字节
            ByteBuffer byteBuffer = readByteBuffer(randomAccessFile, blockSize);
            // 关闭文件
            randomAccessFile.close();
            // 将字节数组转化为字符串
            String line = Charset.forName("utf-8").decode(byteBuffer).toString();
            return line;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return "";
    }

    /**
     * 读取所有文件块
     * @param file
     * @return
     */
    public static String readAllBlock(File file) {

        // 将字节数组转化为字符串
        String line = readBlock(file, 0, Integer.valueOf(file.length() + ""));
        return line;
    }

    /**
     * 读取指定文件块的二进制
     * @param fileName
     * @param startPoint
     * @param blockSize
     * @return
     */
    public static byte[] readBlock(String fileName, long startPoint, int blockSize) {

        File file = new File(fileName);

        if (blockSize == 0) {
            blockSize = Integer.valueOf(file.length() + "");
        }
        try {
            RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
            // 跳转到指定位置
            randomAccessFile.seek(startPoint);
            // 从指定位置读取指定大小的字节
            ByteBuffer byteBuffer = readByteBuffer(randomAccessFile, blockSize);
            // 关闭文件
            randomAccessFile.close();
            return byteBuffer.array();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 读取所有内容
     * @param fileName 文件名称
     * @return
     */
    public static byte[] readAllBlock(String fileName) {

        return readBlock(fileName, 0, 0);
    }

    /**
     * 读取文件中的指定大小文件块
     * @param randomAccessFile
     * @param byteCapacity
     * @return
     * @throws IOException
     */
    public static ByteBuffer readByteBuffer(RandomAccessFile randomAccessFile, int byteCapacity) throws IOException {

        // 读取指定的大小
        byte[] buff = new byte[byteCapacity];
        //Arrays.fill(buff, (byte) 0);
        int read = randomAccessFile.read(buff);
        // 将读取出的内容组织为ByteBuffer
        ByteBuffer buffer = ByteBuffer.allocate(byteCapacity);
        for (int i=0; i<read; i++) {
            buffer.put(buff[i]);
        }
        buffer.flip();
        return buffer;
    }

    /**
     * 文件中追加内容
     * @param fileName
     * @param content
     */
    public static synchronized void writeFileWithStreamByRandomAccess(String fileName, byte[] content) {
        try {
            // 打开一个随机访问文件流，按读写方式
            RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw");
            // 文件长度，字节数
            long fileLength = randomFile.length();
            long fileSize = fileLength;
            // 将写文件指针移到文件尾。
            randomFile.seek(fileLength);
            randomFile.write(content);
            randomFile.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 文件中写入并覆盖原内容
     * @param fileName
     * @param content
     */
    public static synchronized void writeAndOverride(String fileName, byte[] content) {
        try {
            // 打开一个随机访问文件流，按读写方式
            RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw");
            // 将文件指针移到文件的起始位置
            randomFile.seek(0);
            // 清空文件内容
            randomFile.setLength(0);
            // 文件长度，字节数
            long fileLength = randomFile.length();
            long fileSize = fileLength;
            // 将写文件指针移到文件尾。
            randomFile.seek(fileLength);
            randomFile.write(content);
            randomFile.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 文件中写入并覆盖原内容
     * @param fileName
     * @param content
     */
    public static synchronized void writeAndOverride(String fileName, String content) {
        try {
            // 打开一个随机访问文件流，按读写方式
            RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw");
            // 将文件指针移到文件的起始位置
            randomFile.seek(0);
            // 清空文件内容
            randomFile.setLength(0);
            // 文件长度，字节数
            long fileLength = randomFile.length();
            long fileSize = fileLength;
            // 将写文件指针移到文件尾。
            randomFile.seek(fileLength);
            randomFile.write(content.getBytes("utf-8"));
            randomFile.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static synchronized void writeFileWithStreamByRandomAccess(String fileName, String content) {
        try {
            // 打开一个随机访问文件流，按读写方式
            RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw");
            // 文件长度，字节数
            long fileLength = randomFile.length();
            long fileSize = fileLength;
            double size = Math.round(fileSize / 1024.0 / 1024.0 * 100) / 100.0;
            // 将写文件指针移到文件尾。
            randomFile.seek(fileLength);
            randomFile.write(content.getBytes("utf-8"));
            randomFile.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取文件当前写入数
     * @param file
     * @return
     */
    public static long getFilePointer(File file) {
        try {
            RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
            long filePointer = randomAccessFile.getFilePointer();
            return filePointer;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return 0;
    }

    /**
     * 清空文件内容
     * @param file
     */
    public static void emptyFileContent(File file) {
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(file);
            out.write(new byte[0]);
        } catch (Exception e) {

        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    static class FileInfo {
        /**
         * 是否为***.txt类型
         */
        boolean isPreStr = false;

        /**
         * 去除*号后的文件名
         */
        String fileName;

        /**
         * 路径名
         */
        String pathName;

        /**
         * 是否带有*号
         */
        boolean isFuzzy = false;

        /**
         * 是否单纯的文件名不好含*
         */
        boolean isSingleFile = false;

        /**
         * 是否为cz****类型的文件
         */
        boolean isFussixStr = false;

        public boolean isSingleFile() {
            return isSingleFile;
        }

        public void setIsSingleFile(boolean singleFile) {
            isSingleFile = singleFile;
        }

        public boolean isFussixStr() {
            return isFussixStr;
        }

        public void setIsFussixStr(boolean fussixStr) {
            isFussixStr = fussixStr;
        }

        public boolean isPreStr() {
            return isPreStr;
        }

        public void setIsPreStr(boolean preStr) {
            isPreStr = preStr;
        }

        public String getFileName() {
            return fileName;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }

        public String getPathName() {
            return pathName;
        }

        public void setPathName(String pathName) {
            this.pathName = pathName;
        }

        public boolean isFuzzy() {
            return isFuzzy;
        }

        public void setIsFuzzy(boolean fuzzy) {
            isFuzzy = fuzzy;
        }
    }

    /**
     * 解析模糊字符串
     * @param fuzzyPath
     * @return
     */
    public static FileInfo analyzePath(String fuzzyPath) {

        // 将window路径转为/xx/xx/xx形式
        fuzzyPath = fuzzyPath.replaceAll("\\\\", "/");
        String fuzzyFileName = StringUtils.getSplitLast(fuzzyPath, "/");
        String filePath = StringUtils.getSplitNoLast(fuzzyPath, "/");
        // 记录替换前的长度
        int beforeReplaceSize = fuzzyFileName.length();
        String fileName = fuzzyFileName.replaceAll("\\*", "");
        int afterReplaceSize = fileName.length();
        FileInfo fileInfo = new FileInfo();
        fileInfo.setIsFuzzy(!(beforeReplaceSize == afterReplaceSize));
        fileInfo.setIsPreStr(fuzzyFileName.startsWith("\\*"));
        fileInfo.setIsFussixStr(fuzzyFileName.endsWith("\\*"));
        fileInfo.setIsSingleFile(beforeReplaceSize == afterReplaceSize);
        fileInfo.setFileName(fileName);
        fileInfo.setPathName(filePath);
        return fileInfo;
    }

    public static List<IOFileFilter> getFileFilter(String fuzzyPath) {
        List<IOFileFilter> filters = new ArrayList<IOFileFilter>();
        filters.add(FileFilterUtils.fileFileFilter());
        FileInfo fileInfo = analyzePath(fuzzyPath);
        if (fileInfo.isFuzzy() && fileInfo.isPreStr()) {
            filters.add(FileFilterUtils.prefixFileFilter(fileInfo.getFileName()));
        } else if (fileInfo.isFuzzy() && fileInfo.isFussixStr()) {
            filters.add(FileFilterUtils.suffixFileFilter(fileInfo.getFileName()));
        } else if (fileInfo.isSingleFile()) {
            filters.add(FileFilterUtils.nameFileFilter(fileInfo.getFileName()));
        }

        return filters;
    }

    public static FileAlterationObserver getFileObServer(String fuzzyPath) {

        FileInfo fileInfo = analyzePath(fuzzyPath);
        String directory = fileInfo.getPathName();
        AndFileFilter andFileFilter = new AndFileFilter(getFileFilter(fuzzyPath));
        FileAlterationObserver observer = new FileAlterationObserver(directory, andFileFilter);

        return observer;
    }

    /**
     * 获取当前程序运行路径
     * @return
     */
    public static String currentWorkPath() {

        try {
            URL baseClassPath = Thread.currentThread().getContextClassLoader().getResource("");
            String filePath = new File(baseClassPath.getFile()).getCanonicalPath();
            return filePath;
        } catch (IOException e) {
            e.printStackTrace();
        }

        return "";
    }

    public static void main(String[] args) {
        System.out.println(currentWorkPath());
    }
}
